/**
 * 
 */
package org.dse.web;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import org.dse.beans.HtmlDocument;
import org.dse.beans.Webgraph;
import org.dse.dao.HtmlDocumentDAO;
import org.dse.dao.WebgraphDAO;
import org.dse.util.Constants;

/**
 * This class implements the logic to load and store the WebGraph object.
 * 
 * The object of this class will be a singleton in one system running. It is
 * configged in the application context.
 * 
 * The logic gets all links of all pages in the WebGraph, transfers it to the
 * format of database and uses DAO object to store it. The logic also uses DAO
 * object to get data from database, transfers it to WebGraph format.
 * 
 * @author zhangchen
 * 
 */
public class WebGraphDelegateImpl implements WebGraphDelegate {

	private static final String delim = ",";// when store to database, the

	// delimiter of links

	// when reach the fixed length, a new database record
	private static final int TO_STRING_LENGTH = 3000;

	private WebgraphDAO webgraphDao;

	private HtmlDocumentDAO htmlDocumentDao;

	/**
	 * Spring framework IOC. To save or load data to the Webgraph table.
	 */
	public void setWebgraphDao(WebgraphDAO webgraphDao) {
		this.webgraphDao = webgraphDao;
	}

	/**
	 * Spring framework IOC. As a result of the foreign key.
	 */
	public void setHtmlDocumentDao(HtmlDocumentDAO htmlDocumentDao) {
		this.htmlDocumentDao = htmlDocumentDao;
	}

	/**
	 * Rebuild the WebGraph object, and the data is in the database.
	 * 
	 * @return a WebGraph object associated with database
	 */
	public WebGraph rebuildWebGraph() {
		WebGraph graph = new WebGraph();
		List<Webgraph> dbGraphs = webgraphDao.findAll();

		for (Webgraph relation : dbGraphs) {
			String fromLink = relation.getHtmlDocument().getDocUrl();

			String toLinks = relation.getToLinks();

			if (toLinks == null || toLinks.equals("")) {
				graph.addLink(fromLink);
				continue;
			}

			StringTokenizer tokenizer = new StringTokenizer(toLinks, delim);
			while (tokenizer.hasMoreTokens()) {
				graph.addLink(fromLink, tokenizer.nextToken());
			}
		}

		return graph;
	}

	/**
	 * Store the WebGraph data to database, for next time use.
	 * 
	 * @param graph
	 *            the WebGraph object to be stored
	 */
	public void saveWebGraph(WebGraph graph) {
		webgraphDao.deleteAll();

		Set<String> from = graph.availableLink();

		int iter = 0;

		for (String fromDoc : from) {
			Set<String> toLinks = graph.outLinks(fromDoc);
			List<StringBuffer> toStrings = new ArrayList<StringBuffer>();

			StringBuffer to = new StringBuffer("");
			for (String toLink : toLinks) {
				// when reach 3000, a new record
				if (to.length() + toLink.length() >= TO_STRING_LENGTH) {
					toStrings.add(to);
					to = new StringBuffer("");
				}
				to.append(toLink);
				to.append(delim);
			}

			toStrings.add(to);

			for (StringBuffer toString : toStrings) {
				if (toString.length() != 0) {
					// delete the last delimiter
					toString.deleteCharAt(toString.length() - 1);
				}

				Webgraph relation = new Webgraph();// the Webgraph object is an
													// O-R mapping bean
				HtmlDocument document = htmlDocumentDao.findByUrl(fromDoc);
				if (document == null)
					continue;

				relation.setHtmlDocument(document);
				relation.setToLinks(toString.toString());
				webgraphDao.makePersistent(relation);

				if (iter % Constants.BATCH_SIZE == 0) {// in batch mode
					webgraphDao.flush();
					webgraphDao.clear();
				}

				++iter;
			}
		}
	}

}
